#include <stdlib.h>
#include <stdio.h>
#include "list_work.h"

SList *slist_create(int data)
{
    SList *list;
    list = (SList*)malloc(sizeof(SList));
    list->data = data;
    list->next = NULL;
    return list;
}

SList *slist_append(SList *list, int data)
{
    SList* curlist;
    SList* newlist;

    newlist = (SList*) malloc (sizeof(SList));
    newlist->data = data;
    newlist->next = NULL;

    if(list == NULL)
    {
		list = newlist;
        return list;
    }
    curlist = list;
    
	while (curlist->next != NULL)
    {
        curlist = curlist->next;
    }
    curlist->next = newlist;
    return list;
}

SList *slist_prepend(SList *list, int data)
{
    SList* newlist;

    newlist = (SList*) malloc (sizeof(SList));
    newlist->data = data;
    newlist->next = list;
    return newlist;
}

void slist_insert(SList *sibling, int data)
{
        SList* newlist;
        newlist = (SList*) malloc (sizeof(SList));
        newlist->data = data;
        newlist->next = sibling->next;
        sibling->next = newlist;
}

SList *slist_remove(SList *list, int data)
{
        static SList *curlist;
		static SList *buflist;
		static SList *newlist;	
		
       newlist = curlist = list;

	   
		if (curlist->data == data){
			newlist = curlist->next;
			free (curlist);
			return newlist;
		}

		while (curlist->next != 0){
			if (curlist->next->data == data){
				buflist = curlist->next;
				curlist->next = curlist->next->next;
				free(buflist);
			return newlist;
			}
			curlist = curlist->next;
		}
		
		return newlist; 
}

SList *slist_remove_all(SList *list, int data)
{
        SList *curlist;
        SList *buflist;
		SList *newlist;	

        buflist = curlist = list;

		while (curlist->data == data){
			curlist = curlist->next;
			free (buflist);
			buflist = curlist;
		}
		newlist = curlist;

		while (curlist->next != NULL){
			curlist = curlist->next;

			if (curlist->data == data){
				buflist->next = curlist->next;
				free (curlist);
			}
			else{
				buflist = curlist = curlist->next;
			}
		}

		return newlist; 
}

int slist_remove_next(SList *sibling)
{
        int output;
        SList* list_to_delete;
        
		output = sibling->data;
        list_to_delete = sibling->next;
        sibling->next = list_to_delete->next;

        free(list_to_delete);
        return output;
}

void slist_free(SList *list)
{
        SList* buflist;
		SList* newlist;

        newlist = list;

		while(newlist->next != 0)
        {
                buflist = newlist;
                newlist = newlist->next;
                free(buflist);
        }
        
}

unsigned slist_length(SList *list)
{
        unsigned int  i;

        for(i = 0; list != 0; i ++)
        {
                list = list->next;
        }
        return i;
}

SList *slist_copy(SList *list)
{
        SList* copy;
        SList* buflist;
        
		copy = (SList*)malloc(sizeof(SList));
        copy->data = list->data;
		copy->next = (SList*) malloc (sizeof(SList));
        buflist = copy;
        copy = copy->next;
        list = list->next;

        while(list != NULL)
        {
                copy->data = list->data;
                list = list->next;

                if(list!=NULL){
                        copy->next = (SList*) malloc (sizeof (SList));
                        copy = copy->next;
                }
                else
                {
                        copy->next = NULL;
                }
        }
        return buflist;
}

SList *slist_reverse(SList *list)
{
        SList* buflist;
        buflist = (SList*) malloc (sizeof(SList));
        buflist = NULL;
        while(list != 0)
        {
                buflist = slist_prepend(buflist, list->data);
                list = list->next;
        }
        return buflist;
}

SList *slist_concat(SList *list1, SList *list2)
{
        SList *curlist;
        curlist = list1;
        while(curlist->next != NULL){
                curlist = curlist->next;
        }
        curlist->next = list2;
        return list1;
}

void slist_foreach(SList *list, void (*func)(Pointer data, Pointer user_data), int data)
{
        while(list != NULL){
                func((Pointer)list->data, (Pointer)data);
                list = list->next;
        }
}

SList *slist_last(SList *list)
{
        while(list->next != NULL)
        {
                list = list->next;
        }
        return list;
}

SList *slist_nth(SList *list, int n)
{
        int i;

        if(n > 0){
                for(i = 0; i < n-1; i ++)
                {
                        list = list->next;
                }
                return list;
        }
        if(n < 0)
        {
                n = slist_length(list) + n;

                for(i = 0; i < n-1; i ++)
                {
                        list = list->next;
                }
                return list;
        }
}

SList *slist_find(SList *list, int needle)
{
        while(list != NULL){
                if(list->data == needle){
                        return list;
                }
                list = list->next;
        }
        return NULL;
}

SList *slist_find_custom(SList *list, Pointer needle, int (*compare_func)(Pointer a, Pointer b))
{
        while(list != NULL){
                if(compare_func((Pointer)list->data, needle) == 0){
                        return list;
                }
                list=list->next;
        }
}

int slist_position(SList *list, SList *el)
{
        int i;
        for(i = 1; list != NULL; i ++){
                if(list == el){
                        return i;
                }
        }
        return -1;
}